
#define VERSION "0.0"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "mtgorg.h"

#include "cardviewer.h"
#include "pcardviewer.h"
#include "ui_new_deck_dialog.h"
#include "addcarddialog.h"

#include "sqlite3stmt.h"

MTGOrgApp::MTGOrgApp()
  : Q3MainWindow()
{
  if(sqlite3_open_v2("cards.db",&sql,SQLITE_OPEN_READWRITE,0)) {
    qFatal("Could not open database: %s\n",sqlite3_errmsg(sql));
  }
  
  setupUi(this);

  statusBar()->message(tr("Ready."),2000); 
  
  tabChanged();
}

MTGOrgApp::~MTGOrgApp()
{
  sqlite3_close(sql);
}

/*
 *  Sets the strings of the subwidgets using the current
 *  language.
 */
void MTGOrgApp::languageChange()
{
    retranslateUi(this);
}


/////////////////////////////////////////////////////////////////////
// SLOT IMPLEMENTATION
/////////////////////////////////////////////////////////////////////


void MTGOrgApp::fileExit()
{
  statusBar()->message(tr("Exiting application..."));

  qApp->quit();

  statusBar()->message(tr("Ready."),2000);
}

void MTGOrgApp::helpAbout()
{
  QMessageBox::about(this,tr("About..."),
                      tr("MTGOrg\nVersion " VERSION "\n(c) 2008 by Samuel Harrington") );

  statusBar()->message(tr("Ready."),2000);
}

void MTGOrgApp::tabChanged()
{
  statusBar()->message(tr("Loading..."));

  switch(main_tabs->currentPageIndex()) {
    case 0: {
      cbDeck->clear();
      for(sqlite3Stmt stmt(sql,"SELECT dname FROM decks;") ; !stmt.done() ; stmt.step())
        cbDeck->insertItem(stmt.column_text(0));
      deckSwitchDeck("");
    } break;
    case 1: {
      lbSearchReleases->clear();
      lbSearchReleases->insertItem("==ANY==");
      for(sqlite3Stmt stmt(sql,"SELECT rname FROM releases;") ; !stmt.done() ; stmt.step())
        lbSearchReleases->insertItem(stmt.column_text(0));
    } break;
  }

  statusBar()->message(tr("Ready."),2000);
}

void handleAllCheckbox(Q3ButtonGroup* g, int b) {
  if(b==0) {
    const int c = g->count();
    if(g->find(0)->isOn()) {
      for(int i=1; i<c; i++) {
        g->setButton(i);
        g->find(i)->setEnabled(false);
      }
    } else {
      for(int i=1; i<c; i++) {
        g->find(i)->setEnabled(true);
      }
    }
  }
}

void MTGOrgApp::handleAllCheckboxT(int b) {
  handleAllCheckbox(bgType,b);
}

void MTGOrgApp::handleAllCheckboxMT(int b) {
  handleAllCheckbox(bgManaType,b);
}

void MTGOrgApp::handleAllCheckboxR(int b) {
  handleAllCheckbox(bgRarity,b);
}

void add_to_where(QString & s, bool & started, const QString & j, const QString & a) {
  if(started) s += j;
  s += a;
  started = true;
}

void MTGOrgApp::doSearch() {
  
  statusBar()->message(tr("Loading..."));

  bool search_text, search_name, search_type, search_rel;

  if( ! leText->text().isEmpty() ) {
    search_text = cbSearchText->isChecked();
    search_name = cbSearchName->isChecked();
    search_type = cbSearchType->isChecked();
    search_rel = cbSearchRelease->isChecked();    
  }
  else
    search_text = search_name = search_type = search_rel = false;

  bool search_cb_type = !cbTypeAny->isChecked();
  bool search_cb_manat = !cbManaTAny->isChecked();
  bool search_cb_rarity = !cbRarityAny->isChecked();

  bool search_cb_manan = !(cbNMana0->isChecked()&&cbNMana1->isChecked()
                         &&cbNMana2->isChecked()&&cbNMana3->isChecked()
                         &&cbNMana4->isChecked()&&cbNMana5->isChecked()
                         &&cbNMana6->isChecked()&&cbNMana7->isChecked()
                         &&cbNMana8->isChecked()&&cbNManaX->isChecked());

  QString s;
  bool started = false;

  if(search_text||search_name||search_type||search_rel) {
    bool sub_started=false;

    started=true;

    s += "(";
    if(search_text) add_to_where( s, sub_started, " OR ", "text LIKE '%" + leText->text().replace('\'',"''") + "%'" );
    if(search_name) add_to_where( s, sub_started, " OR ", "name LIKE '%" + leText->text().replace('\'',"''") + "%'" );
    if(search_type) add_to_where( s, sub_started, " OR ", "type LIKE '%" + leText->text().replace('\'',"''") + "%'" );
    if(search_rel) add_to_where( s, sub_started, " OR ", "\"group_concat(distinct rname)\" LIKE '%" + leText->text().replace('\'',"''") + "%'" );
    s += ")";
  }

  if(search_cb_type) {
    bool sub_started=false;

    if(started) s += " AND ";
    started=true;

    s += "(";
    if(bgType->find(1)->isOn()) add_to_where( s, sub_started, " OR ", "type LIKE \"%artifact%\"" );
    if(bgType->find(2)->isOn()) add_to_where( s, sub_started, " OR ", "type LIKE \"%creature%\" OR type LIKE \"%summon%\"" );
    if(bgType->find(3)->isOn()) add_to_where( s, sub_started, " OR ", "type LIKE \"%land%\"" );
    if(bgType->find(4)->isOn()) add_to_where( s, sub_started, " OR ", "type LIKE \"%enchant%\"" );
    if(bgType->find(5)->isOn()) add_to_where( s, sub_started, " OR ", "type LIKE \"%sorcery%\"" );
    if(bgType->find(6)->isOn()) add_to_where( s, sub_started, " OR ", "type LIKE \"%interrupt%\"" );
    if(bgType->find(7)->isOn()) add_to_where( s, sub_started, " OR ", "type LIKE \"%instant%\"" );
    if(bgType->find(8)->isOn()) add_to_where( s, sub_started, " OR ", "type LIKE \"%planeswalker%\"" );
    if(!sub_started)
      s += "null";
    s += ")";
  }

  if(search_cb_rarity) {
    QString m;

    if(bgRarity->find(1)->isOn()) m += "C";
    if(bgRarity->find(2)->isOn()) m += "U";
    if(bgRarity->find(3)->isOn()) m += "R";
    if(bgRarity->find(4)->isOn()) m += "S";
    if(!m.isEmpty())
      add_to_where( s, started, " AND ", "\"group_concat(distinct rarity)\" GLOB \"*["+m+"]*\"" );
    else
      add_to_where( s, started, " AND ", "null" );
  }

  if(search_cb_manat) {
    QString m;

    if(bgManaType->find(1)->isOn()) m += "X";
    if(bgManaType->find(2)->isOn()) m += "0-9";
    if(bgManaType->find(3)->isOn()) m += "B";
    if(bgManaType->find(4)->isOn()) m += "W";
    if(bgManaType->find(5)->isOn()) m += "U";
    if(bgManaType->find(6)->isOn()) m += "G";
    if(bgManaType->find(7)->isOn()) m += "R";
    if(!m.isEmpty())
      add_to_where( s, started, " AND ", "mana GLOB \"*["+m+"]*\"" );
    else
      add_to_where( s, started, " AND ", "null" );
  }

  if(search_cb_manan) {
    bool sub_started = false;
    bool range_started = false;
    int begin;

    if(started) s += " AND ";
    started=true;

    s += "(";

    if( bgManaAmount->find(9)->isOn() ) {  // #9 == X == -1
      begin = -1; range_started = true;
    }

    for( int i=0 ; i<9 ; i++ ) {
      if( bgManaAmount->find(i)->isOn() ) {
        if(!range_started ) {
          begin = i; range_started = true;
        }
      }
      else if(range_started) {
        if(begin==i-1) add_to_where( s, sub_started, " OR ", "manan == " + QString::number(begin)  );
        else add_to_where( s, sub_started, " OR ", "manan BETWEEN " + QString::number(begin) + " AND " + QString::number(i-1)  );
        range_started = false;
      }
    }
    if(range_started) {  // Note, #8 is 8+, and it is last, so handle it here
      add_to_where( s, sub_started, " OR ", "manan >= " + QString::number(begin)  );
    }

    if(!sub_started)
      s += "null";

    s += ")";
  }

  if(lbSearchReleases->currentItem()>0) {
    add_to_where( s, started, " AND ", "\"group_concat(distinct rname)\" LIKE '%"+lbSearchReleases->currentText().replace('\'',"''")+"%'"  );
  }

  if(!started) return;
  
  leSql->setText(s);
             
  lvSearchResults->clear();
  for( sqlite3Stmt stmt(sql, "SELECT * FROM card_t_w_ver WHERE " + s + ";" )
     ; !stmt.done()
     ; stmt.step() )
  {
    new Q3ListViewItem( lvSearchResults,
                       stmt.column_text(0),
                       stmt.column_text(1),
                       stmt.column_text(2),
                       stmt.column_text(3),
                       stmt.column_text(4),
                       stmt.column_text(5),
                       stmt.column_text(6),
                       stmt.column_text(7) );
  }
  
  statusBar()->message(tr("Ready."),2000);

}

void MTGOrgApp::searchEditCard() {
  Q3ListViewItem* i = lvSearchResults->selectedItem();
  if(i==0)
    return;

  QString q = "SELECT num FROM card_t WHERE name='"+i->text(0).replace('\'',"''")+"';";

  // Should only get one...
  sqlite3Stmt stmt(sql,q);
  if(!stmt.done()) {
    PCardViewer v(stmt.column_int(0),sql,this,0,TRUE);
    v.exec();
  }
}

void MTGOrgApp::deckNewDeck() {
  QDialog d(this,0,TRUE);
  Ui::new_deck_dialog ui;
  ui.setupUi(&d);

  if(d.exec() && !ui.leText->text().isEmpty()) {
    const QString s = ui.leText->text();
    
    QString s2 = s;
    s2.replace('\'',"''");
    if(sqlite3_exec(sql,"INSERT INTO decks (dname) VALUES('"+s2+"');",0,0,0))
      qWarning("Could not add deck '%s': %s\n",s2.ascii(),sqlite3_errmsg(sql));

    cbDeck->clear();
    for(sqlite3Stmt stmt(sql,"SELECT dname FROM decks;") ; !stmt.done() ; stmt.step())
      cbDeck->insertItem(stmt.column_text(0));

    cbDeck->setCurrentItem(cbDeck->findText(s));

    deckSwitchDeck(s);
  }

}

void MTGOrgApp::deckRemoveDeck() {
  if(!cbDeck->currentText().isEmpty()) {
    if(sqlite3_exec(sql,"DELETE FROM decks WHERE dname='"+cbDeck->currentText()+"';",0,0,0))
      qWarning("Could not delete from deck %s: %s\n",cbDeck->currentText().ascii(),sqlite3_errmsg(sql));
    cbDeck->clear();
    for(sqlite3Stmt stmt(sql,"SELECT dname FROM decks;") ; !stmt.done() ; stmt.step())
      cbDeck->insertItem(stmt.column_text(0));
    deckSwitchDeck("");
  }
}

void MTGOrgApp::deckSwitchDeck(const QString & d_in) {
  QString d = d_in;
  QString s;
  s = "SELECT cards.cnum,";
  s +=      " card_t.name, card_t.type, card_t.mana, card_t.manan, card_t.attack, card_t.defense,";
  s +=      " card_ver.rarity, releases.rname, cards.comments";
  s += " FROM cards, card_t, card_ver, releases, decks";
  s += " WHERE cards.printing=card_ver.oid AND card_ver.card=card_t.num";
  s += " AND releases.rnum=card_ver.ver AND decks.dnum=cards.deck";
  s += " AND decks.dname='"+d.replace('\'',"''")+"';";

  lvDeckCards->clear();

  int n=0;
  for(sqlite3Stmt stmt(sql,s) ; !stmt.done() ; stmt.step()) {
    Q3ListViewItem* i = new Q3ListViewItem( lvDeckCards,
                                         stmt.column_text(0),
                                         stmt.column_text(1),
                                         stmt.column_text(2),
                                         stmt.column_text(3),
                                         stmt.column_text(4),
                                         stmt.column_text(5),
                                         stmt.column_text(6),
                                         stmt.column_text(7) );
    i->setText( 8, stmt.column_text(8) );
    i->setText( 9, stmt.column_text(9) );
    n++;
  }

  nNumDeckCards->display(n);
}

void MTGOrgApp::deckAddCard() {
  AddCardDialog* d = new AddCardDialog(sql,this);

  if(d->exec()) {
    QString q = "INSERT INTO cards (printing) SELECT card_ver.ROWID FROM card_ver, releases, card_t ";
    q += "WHERE card_ver.card==card_t.ROWID ";
    q +=   "AND releases.rnum==card_ver.ver ";
    q +=   "AND releases.rname=='"+d->lbPrintings->currentText().replace('\'',"''")+"' ";
    q +=   "AND card_t.name=='"+d->lbResults->currentText().replace('\'',"''")+"';";

    // Should only get one...
    sqlite3Stmt stmt(sql,q);

    deckSwitchDeck(cbDeck->currentText());
  }
}

void MTGOrgApp::deckEditCard() {
  Q3ListViewItem* i = lvDeckCards->selectedItem();
  if(i==0)
    return;
  CardViewer v(i->text(0).toInt(),sql,this,0,TRUE);
  if(v.exec())
    deckSwitchDeck(cbDeck->currentText());
}

void MTGOrgApp::deckRemoveCard() {
  Q3ListViewItem* i = lvDeckCards->selectedItem();
  if(i==0)
    return;

  QString q = "DELETE FROM cards WHERE cards.ROWID=="+i->text(0)+";";

  // Should only get one...
  sqlite3Stmt stmt(sql,q);
  deckSwitchDeck(cbDeck->currentText());
}

